package cn.iocoder.yudao.module.reading.framework.util;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClientConfig;
import cn.iocoder.yudao.module.infra.framework.file.core.client.db.DBFileClientConfig;
import cn.iocoder.yudao.module.infra.framework.file.core.client.ftp.FtpFileClientConfig;
import cn.iocoder.yudao.module.infra.framework.file.core.client.local.LocalFileClientConfig;
import cn.iocoder.yudao.module.infra.framework.file.core.client.s3.S3FileClientConfig;
import cn.iocoder.yudao.module.infra.framework.file.core.client.sftp.SftpFileClientConfig;
import cn.iocoder.yudao.module.infra.service.file.FileConfigService;
import cn.iocoder.yudao.module.reading.framework.config.StaticResourceProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;

/**
 * 静态资源URL工具类
 * 提供相对路径转完整URL的功能，支持不同环境的域名配置
 * 
 * @author 李晨
 */
@Slf4j
@Component
public class StaticResourceUrlUtils {

    @Resource
    private StaticResourceProperties staticResourceProperties;

    @Resource
    private FileConfigService fileConfigService;

    /**
     * 将相对路径转换为完整的URL
     *
     * @param relativePath 相对路径，如：/reading-app-files/books/pages/xxx.jpeg
     * @return 完整URL，如：http://127.0.0.1:9000/reading-app-files/books/pages/xxx.jpeg
     */
    public String toFullUrl(String relativePath) {
        // 如果路径为空，返回空
        if (StrUtil.isEmpty(relativePath)) {
            return relativePath;
        }

        // 如果已经是完整URL，直接返回
        if (isFullUrl(relativePath)) {
            return relativePath;
        }

        // 检查是否启用URL转换
        Boolean enableUrlConversion = staticResourceProperties.getMinio().getEnableUrlConversion();
        if (enableUrlConversion == null || !enableUrlConversion) {
            log.debug("URL转换已禁用，返回原始路径: {}", relativePath);
            return relativePath;
        }

        // 获取域名配置（优先从数据库获取）
        String domain = getDomainFromDatabase();
        if (StrUtil.isEmpty(domain)) {
            // 如果数据库中没有配置，则从配置文件获取
            domain = staticResourceProperties.getMinio().getDomain();
            if (StrUtil.isEmpty(domain)) {
                log.warn("域名配置为空，请检查数据库文件配置或配置文件中的 yudao.static-resource.minio.domain 配置项，返回原始路径: {}", relativePath);
                return relativePath;
            }
        }

        // 确保域名不以/结尾
        if (domain.endsWith("/")) {
            domain = domain.substring(0, domain.length() - 1);
        }

        // 确保相对路径以/开头
        if (!relativePath.startsWith("/")) {
            relativePath = "/" + relativePath;
        }

        // 检查并处理重复的bucket名称
        String bucketName = staticResourceProperties.getMinio().getBucket();
        if (StrUtil.isNotEmpty(bucketName)) {
            // 如果domain已经包含bucket名称，而relativePath也包含bucket名称，则去掉relativePath中的bucket名称
            String bucketPath = "/" + bucketName;
            if (domain.endsWith(bucketPath) && relativePath.startsWith(bucketPath)) {
                relativePath = relativePath.substring(bucketPath.length());
                if (!relativePath.startsWith("/")) {
                    relativePath = "/" + relativePath;
                }
                log.debug("检测到重复的bucket名称，已处理: domain={}, 处理后的relativePath={}", domain, relativePath);
            }
        }

        String fullUrl = domain + relativePath;
        log.debug("转换URL: {} -> {}", relativePath, fullUrl);

        return fullUrl;
    }

    /**
     * 批量转换相对路径为完整URL
     * 
     * @param relativePaths 相对路径数组
     * @return 完整URL数组
     */
    public String[] toFullUrls(String... relativePaths) {
        if (relativePaths == null) {
            return null;
        }
        
        String[] fullUrls = new String[relativePaths.length];
        for (int i = 0; i < relativePaths.length; i++) {
            fullUrls[i] = toFullUrl(relativePaths[i]);
        }
        
        return fullUrls;
    }

    /**
     * 将完整URL转换为相对路径
     * 主要用于存储到数据库时使用
     *
     * @param fullUrl 完整URL，如：http://127.0.0.1:9000/reading-app-files/books/pages/xxx.jpeg
     * @return 相对路径，如：/reading-app-files/books/pages/xxx.jpeg
     */
    public String toRelativePath(String fullUrl) {
        // 如果URL为空，返回空
        if (StrUtil.isEmpty(fullUrl)) {
            return fullUrl;
        }

        // 如果不是完整URL，直接返回
        if (!isFullUrl(fullUrl)) {
            return fullUrl;
        }

        // 获取域名配置（优先从数据库获取）
        String domain = getDomainFromDatabase();
        if (StrUtil.isEmpty(domain)) {
            // 如果数据库中没有配置，则从配置文件获取
            domain = staticResourceProperties.getMinio().getDomain();
            if (StrUtil.isEmpty(domain)) {
                log.warn("域名配置为空，请检查数据库文件配置或配置文件中的 yudao.static-resource.minio.domain 配置项，返回原始URL: {}", fullUrl);
                return fullUrl;
            }
        }

        // 确保域名不以/结尾
        if (domain.endsWith("/")) {
            domain = domain.substring(0, domain.length() - 1);
        }

        // 如果URL以配置的域名开头，则移除域名部分
        if (fullUrl.startsWith(domain)) {
            String relativePath = fullUrl.substring(domain.length());

            // 对于华为云OBS，domain已经包含bucket信息，不需要再添加bucket前缀
            // 检查domain是否已经包含bucket信息
            String bucketName = staticResourceProperties.getMinio().getBucket();
            if (StrUtil.isNotEmpty(bucketName) && StrUtil.isNotEmpty(domain)) {
                // 如果domain包含bucket名称（如华为云OBS格式），则不添加前缀
                if (domain.contains("." + bucketName + ".") || domain.endsWith("/" + bucketName)) {
                    log.debug("检测到华为云OBS格式domain，跳过添加bucket前缀: domain={}, relativePath={}", domain, relativePath);
                } else {
                    // 传统S3格式，需要添加bucket前缀
                    String bucketPrefix = "/" + bucketName;
                    if (!relativePath.startsWith(bucketPrefix + "/") && !relativePath.equals(bucketPrefix)) {
                        // 移除开头的斜杠（如果有）
                        if (relativePath.startsWith("/")) {
                            relativePath = relativePath.substring(1);
                        }
                        // 添加bucket前缀
                        relativePath = bucketPrefix + "/" + relativePath;
                        log.debug("添加bucket前缀: {} -> {}", fullUrl.substring(domain.length()), relativePath);
                    } else {
                        log.debug("路径已包含bucket前缀，跳过添加: {}", relativePath);
                    }
                }
            }

            log.info("转换为相对路径: {} -> {}", fullUrl, relativePath);
            return relativePath;
        }

        // 如果不匹配当前域名配置，尝试通用的路径提取
        log.warn("URL域名不匹配当前配置，期望域名: {}, 实际URL: {}", domain, fullUrl);

        // 尝试通用的URL路径提取逻辑
        try {
            // 查找第三个斜杠的位置（协议://域名/路径）
            int protocolEnd = fullUrl.indexOf("://");
            if (protocolEnd != -1) {
                int pathStart = fullUrl.indexOf("/", protocolEnd + 3);
                if (pathStart != -1) {
                    String extractedPath = fullUrl.substring(pathStart);

                    // 对于华为云OBS，domain已经包含bucket信息，不需要再添加bucket前缀
                    String bucketName = staticResourceProperties.getMinio().getBucket();
                    if (StrUtil.isNotEmpty(bucketName)) {
                        // 检查是否是华为云OBS格式（通过URL判断）
                        if (fullUrl.contains(".obs.") && fullUrl.contains(".myhuaweicloud.com")) {
                            log.debug("通用逻辑：检测到华为云OBS格式URL，跳过添加bucket前缀: {}", extractedPath);
                        } else {
                            // 传统S3格式，需要添加bucket前缀
                            String bucketPrefix = "/" + bucketName;
                            if (!extractedPath.startsWith(bucketPrefix + "/") && !extractedPath.equals(bucketPrefix)) {
                                // 移除开头的斜杠（如果有）
                                if (extractedPath.startsWith("/")) {
                                    extractedPath = extractedPath.substring(1);
                                }
                                // 添加bucket前缀
                                extractedPath = bucketPrefix + "/" + extractedPath;
                                log.debug("通用逻辑添加bucket前缀: {} -> {}", fullUrl.substring(pathStart), extractedPath);
                            } else {
                                log.debug("通用逻辑：路径已包含bucket前缀，跳过添加: {}", extractedPath);
                            }
                        }
                    }

                    log.info("通过通用逻辑提取路径: {} -> {}", fullUrl, extractedPath);
                    return extractedPath;
                }
            }
        } catch (Exception e) {
            log.error("通用路径提取失败: {}", fullUrl, e);
        }

        // 如果所有方法都失败，返回原URL（这种情况下可能需要手动处理）
        log.error("无法从URL中提取路径，返回原始URL: {}", fullUrl);
        return fullUrl;
    }

    /**
     * 判断是否为完整URL
     * 
     * @param url URL字符串
     * @return true-完整URL，false-相对路径
     */
    private boolean isFullUrl(String url) {
        return StrUtil.isNotEmpty(url) && (url.startsWith("http://") || url.startsWith("https://"));
    }

    /**
     * 获取当前配置的Minio域名
     * 优先从数据库获取，如果数据库中没有配置则从配置文件获取
     *
     * @return Minio域名，如果未配置则返回null
     */
    public String getMinioDomain() {
        // 优先从数据库获取domain
        String domain = getDomainFromDatabase();
        if (StrUtil.isNotEmpty(domain)) {
            return domain;
        }

        // 如果数据库中没有配置，则从配置文件获取
        domain = staticResourceProperties.getMinio().getDomain();
        if (StrUtil.isEmpty(domain)) {
            log.warn("域名配置为空，请检查数据库文件配置或配置文件中的 yudao.static-resource.minio.domain 配置项");
        }
        return domain;
    }

    /**
     * 从数据库获取主文件配置的domain
     *
     * @return domain，如果获取失败则返回null
     */
    private String getDomainFromDatabase() {
        try {
            FileConfigDO masterConfig = fileConfigService.getMasterFileConfig();
            if (masterConfig == null) {
                log.debug("数据库中没有主文件配置");
                return null;
            }

            FileClientConfig config = masterConfig.getConfig();
            if (config == null) {
                log.debug("主文件配置中没有config信息");
                return null;
            }

            // 根据不同的配置类型提取domain
            String domain = extractDomainFromConfig(config);
            if (StrUtil.isNotEmpty(domain)) {
                log.debug("从数据库获取到domain: {}", domain);
                return domain;
            }

            log.debug("主文件配置中没有domain信息");
            return null;
        } catch (Exception e) {
            log.warn("从数据库获取domain失败，将使用配置文件中的配置", e);
            return null;
        }
    }

    /**
     * 从FileClientConfig中提取domain
     *
     * @param config 文件客户端配置
     * @return domain，如果提取失败则返回null
     */
    private String extractDomainFromConfig(FileClientConfig config) {
        if (config instanceof S3FileClientConfig) {
            return ((S3FileClientConfig) config).getDomain();
        } else if (config instanceof LocalFileClientConfig) {
            return ((LocalFileClientConfig) config).getDomain();
        } else if (config instanceof DBFileClientConfig) {
            return ((DBFileClientConfig) config).getDomain();
        } else if (config instanceof FtpFileClientConfig) {
            return ((FtpFileClientConfig) config).getDomain();
        } else if (config instanceof SftpFileClientConfig) {
            return ((SftpFileClientConfig) config).getDomain();
        } else {
            log.warn("未知的FileClientConfig类型: {}", config.getClass().getName());
            return null;
        }
    }

    /**
     * 获取当前配置的存储桶名称
     *
     * @return 存储桶名称，如果未配置则返回null
     */
    public String getBucketName() {
        String bucket = staticResourceProperties.getMinio().getBucket();
        if (StrUtil.isEmpty(bucket)) {
            log.warn("Minio存储桶配置为空，请检查配置文件中的 yudao.static-resource.minio.bucket 配置项");
        }
        return bucket;
    }

    /**
     * 检查配置是否完整
     * 优先检查数据库配置，如果数据库中没有配置则检查配置文件
     *
     * @return true-配置完整，false-配置不完整
     */
    public boolean isConfigurationValid() {
        // 优先检查数据库配置
        String domain = getDomainFromDatabase();
        if (StrUtil.isEmpty(domain)) {
            // 如果数据库中没有配置，则检查配置文件
            domain = staticResourceProperties.getMinio().getDomain();
        }

        String bucket = staticResourceProperties.getMinio().getBucket();
        Boolean enableUrlConversion = staticResourceProperties.getMinio().getEnableUrlConversion();

        boolean isValid = StrUtil.isNotEmpty(domain) && StrUtil.isNotEmpty(bucket) && enableUrlConversion != null;

        if (!isValid) {
            log.error("静态资源配置不完整，请检查以下配置项：");
            if (StrUtil.isEmpty(domain)) {
                log.error("  - 数据库文件配置中的domain字段或配置文件中的yudao.static-resource.minio.domain");
            }
            if (StrUtil.isEmpty(bucket)) {
                log.error("  - yudao.static-resource.minio.bucket");
            }
            if (enableUrlConversion == null) {
                log.error("  - yudao.static-resource.minio.enable-url-conversion");
            }
        }

        return isValid;
    }
}
